#include "statsxx/machine_learning/NeuralNet.hpp"

// STL
#include <iostream>


//
// DESC: Perform backward propagation of errors at time t-i, given actual output and calculated output at t == 0.
//
inline void NEURAL_NET::backward_prop(int i, const std::vector<double> &actual_out, const std::vector<double> &calc_out)
{
//    std::cout << "starting backprop ..." << std::endl;

    // LOAD ERROR AND GET ``TOP NEURONS'' ...
    std::vector<int> top_neurons;

    if( i == 0 )
    {
        for( auto n : m_out_neurons )
        {
            top_neurons.push_back(n);
        }

        this->load_output_errors(actual_out, calc_out);
    }
    else
    {
        this->assign_recurrent_errors(top_neurons);

        this->find_source_neurons(top_neurons, false);

        this->activate_neurons(top_neurons, false);
    }

    /*
    // ****
    std::cout << "here 999879" << std::endl;
    for( auto n : top_neurons )
    {
        std::cout << "n: " << n << std::endl;
    }
    // *****
    */


    // ... AND THEN, WHILE TOP NEURONS POINT DOWN TO OTHER NEURONS (NOT JUST INPUT OR BIAS), PROPAGATE DOWN ...
    while( neurons_pt_to_neurons(top_neurons, false) )
    {
        // PROPAGATE SIGNAL (ERROR) DOWNSTREAM, KEEPING A ``HIT LIST'' OF IDs OF ALL NEURONS HIT ...
        std::vector<int> ID_hit_list;
        for( auto &n : top_neurons )
        {
            propagate_signal(m_neurons[n], ID_hit_list, false);
        }

        /*
        // ****
        std::cout << "NEURONS HIT ::::::" << std::endl;
        for( auto n : ID_hit_list )
        {
            std::cout << "n: " << n << std::endl;
        }
        // *****
        */

        this->find_source_neurons(ID_hit_list, false);

        /*
        // ****
        std::cout << "NEURONS HIT / DUP REM ::::::" << std::endl;
        for( auto n : ID_hit_list )
        {
            std::cout << "n: " << n << std::endl;
        }
        // *****
        */

        this->activate_neurons(ID_hit_list, false);

        top_neurons.clear();
        for( auto ID : ID_hit_list )
        {
            top_neurons.push_back(ID);
        }
    }

    // UPON EXITING THE WHILE LOOP, THE TOP NEURONS POINT TO THE INACTIVE INPUT OR BIAS NEURONS (NO NEED TO WORRY ABOUT THESE) ...

//    std::cout << "ending backprop ..." << std::endl;
//    int fgj; std::cin >> fgj;
}
